import { Context, Next } from 'koa'
import { BaseException } from './BaseException'
import { ResponseUtil } from '../utils/ResponseUtil'
import { Logger } from '../logger/Logger'

/**
 * 错误处理中间件
 * 统一捕获和处理应用中的所有异常
 */
export class ErrorHandler {
  /**
   * 生成唯一的错误追踪ID
   * @returns 唯一错误ID
   */
  private static generateErrorId(): string {
    // 使用更健壮的错误ID生成方式
    return `${Date.now().toString(36)}-${Math.random()
      .toString(36)
      .substring(2, 10)}`
  }

  /**
   * 清理敏感信息的请求头
   * @param headers 原始请求头
   * @returns 清理后的请求头
   */
  private static sanitizeHeaders(
    headers: Record<string, any>
  ): Record<string, any> {
    const sensitiveHeaders = ['authorization', 'cookie', 'x-api-key', 'token']
    const sanitized: Record<string, any> = {}

    for (const [key, value] of Object.entries(headers || {})) {
      if (
        sensitiveHeaders.some((sensitive) =>
          key.toLowerCase().includes(sensitive)
        )
      ) {
        sanitized[key] = '******'
      } else {
        sanitized[key] = value
      }
    }

    return sanitized
  }

  /**
   * 安全地序列化请求体
   * @param body 请求体
   * @returns 序列化后的字符串或undefined
   */
  private static safeStringifyBody(body: any): string | undefined {
    if (!body) return undefined

    try {
      // 限制序列化对象大小
      const stringified = JSON.stringify(body)
      // 如果序列化后的字符串过大，返回截断版本
      if (stringified.length > 1000) {
        return stringified.substring(0, 1000) + '... (truncated)'
      }
      return stringified
    } catch {
      return '[无法序列化的请求体]'
    }
  }

  /**
   * 记录结构化错误日志
   * @param ctx Koa上下文
   * @param error 错误对象
   * @param errorId 错误追踪ID
   */
  private static logError(ctx: Context, error: any, errorId: string): void {
    try {
      // 构建详细的错误日志信息，确保所有字段都有默认值
      const logData = {
        errorId,
        message: error?.message || String(error || '未知错误'),
        stack: error?.stack || undefined,
        // 错误类型信息
        errorType: error?.constructor?.name || 'UnknownError',
        url: ctx.url || '',
        method: ctx.method || '',
        // 清理敏感信息的请求头
        headers: this.sanitizeHeaders(ctx.headers),
        query: ctx.query || {},
        // 安全序列化请求体
        body: this.safeStringifyBody((ctx.request as any).body),
        ip: ctx.ip || '',
        timestamp: new Date().toISOString()
      }

      // 使用统一日志管理系统记录错误
      const errorLogger = Logger.error
      errorLogger.error(`[Error ID: ${errorId}] Error occurred:`, logData)
    } catch (loggingError) {
      // 防止日志记录本身失败导致整个错误处理流程中断
      try {
        const errorLogger = Logger.error
        errorLogger.error(
          `Failed to log error with ID ${errorId}:`,
          loggingError
        )
      } catch (fatalError) {
        // 最后防线，使用原始console
        console.error(`Fatal error in error logging:`, fatalError)
      }
    }
  }

  /**
   * 设置错误响应的通用方法
   * @param ctx Koa上下文
   * @param status 状态码
   * @param message 错误消息
   * @param data 错误数据
   */
  private static setErrorResponse(
    ctx: Context,
    status: number,
    message: string,
    data: any
  ): void {
    try {
      ctx.status = status
      // 更简单的方式：直接构建符合ResponseUtil.error接口的响应
      const errorMessage = typeof data === 'string' ? data : undefined
      ResponseUtil.error(ctx, message, errorMessage, status)

      // 安全地将data添加到响应体中
      if (
        data &&
        typeof data === 'object' &&
        ctx.body &&
        typeof ctx.body === 'object'
      ) {
        ;(ctx.body as any).data = data
      }
    } catch (responseError) {
      // 防止响应设置失败
      console.error('Failed to set error response:', responseError)
      // 尝试直接设置响应
      ctx.status = status
      ctx.body = { success: false, message, data, code: status }
    }
  }

  /**
   * 错误处理中间件函数
   */
  public static async handleError(ctx: Context, next: Next): Promise<void> {
    // 直接使用类名调用静态方法，避免this上下文问题
    const errorId = ErrorHandler.generateErrorId()

    try {
      // 设置错误ID到响应头，便于追踪
      ctx.set('X-Error-ID', errorId)

      // 执行后续中间件
      await next()
    } catch (error) {
      try {
        // 记录详细错误日志
        ErrorHandler.logError(ctx, error, errorId)

        // 确保错误对象是有效的
        const errorObj = error || new Error('未知错误')

        // 如果是自定义异常
        if (errorObj instanceof BaseException) {
          const statusCode = errorObj.status || 500

          // 构建错误响应数据，确保所有属性都存在
          const errorResponse = {
            errorId,
            message: errorObj.message || '自定义异常',
            code: errorObj.code || statusCode,
            details: errorObj.details || null
          }

          return ErrorHandler.setErrorResponse(
            ctx,
            statusCode,
            errorResponse.message,
            errorResponse
          )
        }

        // 确保错误对象有必要的属性
        const standardError = errorObj as Error
        const errorName = standardError.name || ''
        const errorMessage = standardError.message || '未知错误'

        // 细化错误分类处理
        switch (errorName) {
          case 'ValidationError':
            return ErrorHandler.setErrorResponse(ctx, 400, '数据验证失败', {
              errorId,
              message: errorMessage
            })
          case 'SyntaxError':
            return ErrorHandler.setErrorResponse(ctx, 400, '请求格式错误', {
              errorId,
              message: '无效的JSON格式'
            })
          case 'TypeError':
            return ErrorHandler.setErrorResponse(
              ctx,
              400,
              '参数类型错误',
              process.env.NODE_ENV === 'development'
                ? { errorId, message: errorMessage }
                : { errorId }
            )
          default:
            // 未预期的错误（兜底处理）
            return ErrorHandler.setErrorResponse(
              ctx,
              500,
              '服务器内部错误',
              process.env.NODE_ENV === 'development'
                ? {
                    errorId,
                    message: errorMessage,
                    stack: standardError.stack || undefined,
                    errorType: errorName || 'UnknownError'
                  }
                : { errorId }
            )
        }
      } catch (fatalError) {
        // 最终兜底，确保至少返回500错误
        console.error('Fatal error in error handler:', fatalError)
        ctx.status = 500
        ctx.body = {
          success: false,
          message: '服务器内部错误',
          data: { errorId },
          code: 500
        }
      }
    }
  }

  /**
   * 404处理中间件
   */
  public static async handleNotFound(ctx: Context, next: Next): Promise<void> {
    try {
      await next()

      // 如果没有匹配到路由，返回404错误
      if (ctx.status === 404 && !ctx.body) {
        // 使用类名调用静态方法，避免this上下文问题
        const errorId = ErrorHandler.generateErrorId()
        ctx.set('X-Error-ID', errorId)

        // 记录404日志
        console.warn(
          `[Error ID: ${errorId}] 404 Not Found: ${ctx.method} ${ctx.url} from ${ctx.ip}`
        )

        return ErrorHandler.setErrorResponse(ctx, 404, '请求的接口不存在', {
          errorId,
          path: ctx.url,
          method: ctx.method
        })
      }
    } catch (error) {
      // 处理404中间件自身的错误
      console.error('Error in 404 handler:', error)
      ctx.status = 500
      ctx.body = { success: false, message: '服务器内部错误', code: 500 }
    }
  }

  /**
   * 健康检查中间件
   * 用于监控系统状态
   */
  public static async healthCheck(ctx: Context, next: Next): Promise<void> {
    try {
      if (ctx.path === '/health' && ctx.method === 'GET') {
        ctx.status = 200
        ctx.body = {
          success: true,
          message: '服务运行正常',
          data: {
            timestamp: new Date().toISOString(),
            env: process.env.NODE_ENV || 'development',
            version: process.env.APP_VERSION || 'unknown'
          },
          code: 200
        }
        return
      }
      await next()
    } catch (error) {
      // 处理健康检查中间件自身的错误
      console.error('Error in health check middleware:', error)
      // 继续传递错误给错误处理中间件
      throw error
    }
  }
}
